{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### PCA 主成分分析\n",
    "\n",
    "> 理论 《统计学习方法》第16章 主成分分析\n",
    ">\n",
    "> 代码 numpy version && torch version\n",
    ">\n",
    "> Python3.7\n",
    ">\n",
    "> created 2023/02/14\n",
    ">\n",
    "> author lyz\n",
    ">\n",
    "> email 2281250383@qq.com"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "\n",
    "#_*_ coding:utf-8_*_\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import cv2\n",
    "from sklearn.decomposition import PCA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "outputs": [],
   "source": [
    "X = np.array(\n",
    "[[66, 64, 65, 65, 65],\n",
    " [65, 63, 63, 65, 64],\n",
    " [57, 58, 63, 59, 66],\n",
    " [67, 69, 65, 68, 64],\n",
    " [61, 61, 62, 62, 63],\n",
    " [64, 65, 63, 63, 63],\n",
    " [64, 63, 63, 63, 64],\n",
    " [63, 63, 63, 63, 63],\n",
    " [65, 64, 65, 66, 64],\n",
    " [67, 69, 69, 68, 67],\n",
    " [62, 63, 65, 64, 64],\n",
    " [68, 67, 65, 67, 65],\n",
    " [65, 65, 66, 65, 64],\n",
    " [62, 63, 64, 62, 66],\n",
    " [64, 66, 66, 65, 67]]\n",
    ")"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "使用numpy实现的PCA"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "outputs": [],
   "source": [
    "class PCA_numpy(object):\n",
    "    def __init__(self):\n",
    "       pass\n",
    "\n",
    "    \"\"\"\n",
    "        求主成分\n",
    "        threshold可选参数表示方差累计达到threshold后就不再取后面的特征向量\n",
    "    \"\"\"\n",
    "    def principal_comps(self,dataset ,threshold = 0.85):\n",
    "        dataset = np.matrix(dataset,dtype='float64').T\n",
    "\n",
    "        res = []\n",
    "        data = []\n",
    "\n",
    "        # 标准化\n",
    "        for i,line in enumerate(dataset):\n",
    "            dataset[i] -= np.mean(line)\n",
    "            dataset[i] /= np.std(line,ddof=1)\n",
    "\n",
    "        # 求协方差矩阵\n",
    "        cov = np.cov(dataset)\n",
    "        # 求特征值和特征向量\n",
    "        eigs,vectors = np.linalg.eig(cov)\n",
    "        # 第i个特征向量是第i列，\n",
    "        for i in range(len(eigs)):\n",
    "            data.append((eigs[i],vectors[:,i].T))\n",
    "        # 按照特征值从小到大进行排序\n",
    "        data.sort(key=lambda  x:x[0], reverse=True)\n",
    "\n",
    "        sum = 0\n",
    "        for comp in data:\n",
    "            sum += comp[0] / np.sum(eigs)\n",
    "            res.append(\n",
    "                tuple(map(\n",
    "                    lambda x:np.round(x,5),\n",
    "\t                (comp[1],comp[0] / np.sum(eigs),sum)\n",
    "                ))\n",
    "            )\n",
    "            print('特征值:{:.4f}; 特征向量：{}； 方差贡献率：{}; 累计方差贡献率:{}'.format(comp[0],res[-1][0],res[-1][1],res[-1],[2]))\n",
    "            if sum > threshold:\n",
    "                return res\n",
    "\n",
    "        return res\n"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "特征值:3.4532; 特征向量：[0.48198 0.51227 0.45384 0.51336 0.18914]； 方差贡献率：0.69064; 累计方差贡献率:(array([0.48198, 0.51227, 0.45384, 0.51336, 0.18914]), 0.69064, 0.69064)\n",
      "特征值:1.2231; 特征向量：[ 0.33297  0.13247 -0.39212  0.20476 -0.82213]； 方差贡献率：0.24462; 累计方差贡献率:(array([ 0.33297,  0.13247, -0.39212,  0.20476, -0.82213]), 0.24462, 0.93525)\n",
      "\n",
      "[(array([0.48198, 0.51227, 0.45384, 0.51336, 0.18914]), 0.69064, 0.69064), (array([ 0.33297,  0.13247, -0.39212,  0.20476, -0.82213]), 0.24462, 0.93525)]\n"
     ]
    }
   ],
   "source": [
    "p = PCA_numpy()\n",
    "lst = p.principal_comps(X)\n",
    "print()\n",
    "print(lst)"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 使用sklearn实现的PCA"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-1.51394918 -0.21382815]\n",
      " [ 0.25137676 -1.8134245 ]\n",
      " [10.61577071  2.68155382]\n",
      " [-6.48520841 -1.16575919]\n",
      " [ 5.53026102 -1.52083322]\n",
      " [ 0.70154125 -1.8544697 ]\n",
      " [ 1.82460091 -1.29624147]\n",
      " [ 2.44281085 -1.60484093]\n",
      " [-1.40146605 -0.59189041]\n",
      " [-7.76925956  3.34817657]\n",
      " [ 1.8850487   0.61749314]\n",
      " [-5.41819247 -0.9163256 ]\n",
      " [-1.764172    0.155228  ]\n",
      " [ 3.06230672  1.51679123]\n",
      " [-1.96146925  2.65837042]]\n",
      "\n",
      "[0.82399563 0.11748567]\n"
     ]
    }
   ],
   "source": [
    "# n_components 指明了降到几维\n",
    "pca = PCA(n_components = 2)\n",
    "\n",
    "# 利用数据训练模型（即上述得出特征向量的过程）\n",
    "pca.fit(X)\n",
    "\n",
    "# 得出原始数据的降维后的结果；也可以以新的数据作为参数，得到降维结果。\n",
    "print(pca.transform(X))\n",
    "print()\n",
    "# 打印各主成分的方差占比\n",
    "print(pca.explained_variance_ratio_)"
   ],
   "metadata": {
    "collapsed": false
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "3.9.6"
  },
  "vscode": {
   "interpreter": {
    "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
